<template>
  <div class="table-wrap">
    <FilterHeader @search="search" />
    <div class="tableWrap">
      <Contextmenu ref="contextmenu">
        <template #color="{ item }">
          <span
            class="vxe-context-menu--link-content"
            @click.stop="
              item.lastColor &&
                item.emit('OptionClick', {
                  code: item.children[0].code,
                  childrenCode: item.lastColor,
                })
            "
          >
            {{ item.name }}
            <span
              class="color"
              style="border-radius: 1px; width: 6px; height: 12px; display: inline-block"
              :style="{ backgroundColor: item.lastColor }"
              v-if="item.lastColor"
            ></span>
          </span>

          <i class="vxe-context-menu--link-suffix suffix--haschild"></i>
          <ul class="vxe-table--context-menu-clild-wrapper" v-if="!item.disabled">
            <li
              @click.stop="
                item.emit('OptionClick', { code: item.children[0].code, childrenCode: 'none' })
              "
            >
              <div class="menu-item">无填充</div>
            </li>
            <li>
              <div class="colorpicer menu-item">
                <div class="colortitle" @click.stop>主题颜色</div>
                <div class="colorWrap">
                  <div
                    class="colorItem"
                    v-for="color in item.children"
                    :key="color.name"
                    :style="{
                      backgroundColor: color.name,
                      border:
                        item.lastColor === color.name ? '1px solid #000' : '1px solid transparent',
                    }"
                    @click.stop="
                      item.emit('OptionClick', {
                        ...color,
                        clickCode: (item.code ?? '') + color.code,
                      })
                    "
                  ></div>
                </div>
              </div>
            </li>
          </ul>
        </template>
      </Contextmenu>
      <div class="tableHeader">
        <vxe-grid
          ref="xGridHeader"
          v-bind="gridOptions"
          :row-config="rowHeight"
          :data="Array.from(store.$state.fixRow)"
          :columns="filterColunms"
          :scroll-y="{ enabled: false, gt: 0 }"
          :cell-style="setCellStyle"
          :row-style="setRowStyle"
          :sort-config="{ multiple: true }"
          :mouse-config="{ selected: true }"
          :show-overflow="true"
          :menu-config="{
            body: {
              options: [
                [
                  {
                    code: 'fix',
                    name: '冻结此行',
                    disabled: false,
                  },
                ],
              ],
            },
          }"
          @sort-change="({ field, order }) => xGrid?.sort({ field, order })"
          @filter-change="
            params => {
              const column = xGrid?.getColumnByField(params.column.field);
              if (column) {
                params.column.filters.forEach(
                  (filter, index) => (column.filters[index].checked = filter.checked)
                );
                xGrid?.updateData();
              }
            }
          "
        >
          <template #empty></template>
          <template #toolbar>
            <div class="toolbar">
              <div class="left-tool">
                <div class="title">这是表格标题</div>
                <div class="total">
                  共
                  <div class="num">{{ filterList.length }}</div>
                  条数据
                </div>

                <vxe-pager
                  :align="'left'"
                  size="small"
                  v-model:current-page="page.currentPage"
                  v-model:page-size="page.pageSize"
                  :total="page.total"
                  :page-sizes="[
                    10, 20, 50, 100, 200, 500,
                    // { label: '大量数据', value: 1000 },
                    // { label: '全量数据', value: -1 },
                  ]"
                  :layouts="[
                    'PrevJump',
                    'PrevPage',
                    'Number',
                    'NextPage',
                    'NextJump',
                    'Sizes',
                    'FullJump',
                  ]"
                  @page-change="pageChange"
                ></vxe-pager>

                <el-tooltip content="导出">
                  <img
                    :src="ExcelSvgIcon"
                    class="download icon"
                    aria-hidden="true"
                    style="
                      cursor: pointer;
                      display: inline-block;
                      width: 16px;
                      height: 16px;
                      margin-left: 8px;
                    "
                    title="导出"
                    @click="download"
                  />
                </el-tooltip>
              </div>
              <div class="right-tool">
                <vxe-input
                  v-model="searchText"
                  placeholder="请搜索"
                  clearable
                  size="small"
                  @keyup="searchEvent"
                >
                  <template #prefix>
                    <span class="iconfont icon-sousuo"></span>
                  </template>
                </vxe-input>

                <!-- <ColumnOperatorBtn :columns="columns" @columnAction="columnAction" /> -->
                <ColumnDargBtn :columns="columns" @columsChange="columsChange" />
                <el-dropdown
                  :hide-on-click="false"
                  size="small"
                  style="margin-left: 12px"
                  trigger="click"
                >
                  <span
                    class="toolIcon iconfont icon-kuangao"
                    name="num-list"
                    @click="clickEvent3"
                    title="行高"
                  ></span>
                  <template #dropdown>
                    <div class="listwrap">
                      <div class="list-group-item" style="cursor: pointer" @click="setHeight(38)">
                        默认
                      </div>
                      <div class="list-group-item" style="cursor: pointer" @click="setHeight(42)">
                        宽松
                      </div>
                      <div class="list-group-item" style="cursor: pointer" @click="setHeight(34)">
                        紧凑
                      </div>
                    </div>
                  </template>
                </el-dropdown>
                <span
                  title="刷新"
                  class="toolIcon iconfont icon-shuaxin"
                  name="refresh"
                  @click="toolbarToolClick('refresh')"
                ></span>
                <span
                  title="全屏"
                  class="toolIcon iconfont icon-quanping"
                  name="refresh"
                  @click="toolbarToolClick('fullscreen')"
                ></span>
              </div>
            </div>
          </template>

          <template #name_edit="{ row }">
            <vxe-input v-model="row.name"></vxe-input>
          </template>
          <template #nickname_edit="{ row }">
            <vxe-input v-model="row.nickname"></vxe-input>
          </template>
          <template #role_edit="{ row }">
            <vxe-input v-model="row.role"></vxe-input>
          </template>
          <template #address_edit="{ row }">
            <vxe-input v-model="row.address"></vxe-input>
          </template>
          <template #status="{ row }">
            <StatusText :status-text="row.status" />
          </template>
          <!-- 操作栏 -->
          <template #operator_buttons="{ row }">
            <div class="operator-wrap">
              <vxe-button
                type="text"
                status="primary"
                @click="open(1)"
                content="操作一"
              ></vxe-button>
              <div class="divied-line"></div>
              <vxe-button
                type="text"
                status="primary"
                @click="open(2)"
                content="操作二"
              ></vxe-button>
              <div class="divied-line"></div>
              <MoreBtn />
            </div>
          </template>
        </vxe-grid>
      </div>
      <div class="tableBody">
        <!--  -->
        <vxe-grid
          ref="xGrid"
          v-bind="gridOptions"
          :show-header="false"
          :row-config="rowHeight"
          :data="tableData"
          :loading="loading"
          :columns="filterColunms"
          :scroll-y="{ enabled: true, gt: 0 }"
          :cell-style="setCellStyle"
          @scroll="({scrollLeft, scrollTop}) => xGridHeader!.scrollTo(scrollLeft, scrollTop)"
          :row-style="setRowStyle"
          :sort-config="{ multiple: true }"
          :mouse-config="{ selected: true }"
          max-height="100%"
          :show-overflow="true"
          :menu-config="{
            body: {
              options: [
                [
                  {
                    code: 'fix',
                    name: '冻结此行',
                    disabled: false,
                  },
                ],
              ],
            },
          }"
        >
          <template #toolbar></template>
          <template #name_edit="{ row }">
            <vxe-input v-model="row.name"></vxe-input>
          </template>
          <template #nickname_edit="{ row }">
            <vxe-input v-model="row.nickname"></vxe-input>
          </template>
          <template #role_edit="{ row }">
            <vxe-input v-model="row.role"></vxe-input>
          </template>
          <template #address_edit="{ row }">
            <vxe-input v-model="row.address"></vxe-input>
          </template>
          <template #status="{ row }">
            <StatusText :status-text="row.status" />
          </template>
          <!-- 操作栏 -->
          <template #operator_buttons="{ row }">
            <div class="operator-wrap">
              <vxe-button
                type="text"
                status="primary"
                @click="open(1)"
                content="操作一"
              ></vxe-button>
              <div class="divied-line"></div>
              <vxe-button
                type="text"
                status="primary"
                @click="open(2)"
                content="操作二"
              ></vxe-button>
              <div class="divied-line"></div>
              <MoreBtn />
            </div>
          </template>
        </vxe-grid>
      </div>
    </div>
  </div>
</template>

<script lang="tsx" setup>
import { reactive } from 'vue';
import type {
  VxeGridProps,
  VxeGridListeners,
  VxeGridInstance,
  VxePulldownInstance,
  VxePagerDefines,
  VxeTablePropTypes,
} from 'vxe-table';
import { VXETable } from 'vxe-table';
import FilterContent from './components/FilterContent.vue';
import FilterHeader from './components/FilterHeader.vue';
import ColumnDargBtn from './components/ColumnDargBtn.vue';
import Contextmenu from './components/Contextmenu.vue';
import MoreBtn from './components/MoreBtn.vue';
import StatusText from './components/StatusText.vue';
import { columnsData } from './conifg';
import {
  vxeMenuRegister,
  vxeCommandRegister,
  menuConfig,
  setCellStyle,
  equalRow,
  setRowStyle,
} from './utils/utils';
import { useMainStore } from '@/stores/main';
import { list } from './utils/mock';
import { ElMessage, ElMessageBox, type Action } from 'element-plus';
import ExcelSvgIcon from '@/assets/imgs/excel.svg';
const store = useMainStore();
const filterList = ref(JSON.parse(JSON.stringify(list)));

onMounted(() => {
  vxeCommandRegister();
  vxeMenuRegister();
});
const dialogVisible = ref(false);
const contextmenu = ref();
const loading = ref<boolean>(false);
const searchText = ref<string>('');
const xGrid = ref<VxeGridInstance<RowVO>>();
const xGridHeader = ref<VxeGridInstance<RowVO>>();
const pulldownRef = ref<VxePulldownInstance>();
const rowHeight = ref<VxeTablePropTypes.RowConfig>({ height: 38, isHover: true, useKey: true });
let columns = ref<any[]>(columnsData);
const filterColunms = computed(() => {
  return columns.value.filter(item => !item.hide);
});
const clickEvent3 = () => {
  const $pulldown = pulldownRef.value;
  if ($pulldown) {
    $pulldown.togglePanel();
  }
};
interface RowVO {
  id: number;
  name: string;
  nickname: string;
  role: string;
  sex: string;
  age: number;
  address: string;
}
const page = ref({
  currentPage: 1,
  pageSize: 20,
  total: 500,
});

const getCurrentPageData = () => {
  loading.value = true;
  setTimeout(() => {
    const { currentPage, pageSize } = page.value;
    const fixRow = Array.from(store.$state.fixRow ?? []);

    tableData.value = filterList.value
      .slice((currentPage - 1) * pageSize, currentPage * pageSize)
      .filter((e: any) => !fixRow.some(item => equalRow(item, e)));

    loading.value = false;
  }, 300);
};

const tableData = ref<any[]>([]);
const download = () => {
  const $grid = xGrid.value!;
  VXETable.commands.get('exportXLSX').commandMethod!(
    {
      code: 'exportXLSX',
      button: void 0,
      $table: $grid as any,
      $grid
    },
    { header: xGridHeader.value! }
  );
};
const searchEvent = () => {
  const filterVal = String(searchText.value).trim().toLowerCase();
  const { currentPage, pageSize } = page.value;
  const listData = filterList.value.slice((currentPage - 1) * pageSize, currentPage * pageSize);
  if (filterVal && listData.length) {
    const filterRE = new RegExp(filterVal, 'gi');
    const searchProps = Object.keys(listData[0]).filter(item => !['status'].includes(item));
    const rest = listData.filter(item =>
      searchProps.some(key => String(item[key]).toLowerCase().indexOf(filterVal) > -1)
    );
    tableData.value = rest.map(row => {
      const item = Object.assign({}, row);
      searchProps.forEach(key => {
        item[key] = String(item[key]).replace(
          filterRE,
          match => `<span class="keyword-lighten">${match}</span>`
        );
      });
      return item;
    });
  } else {
    tableData.value = listData;
  }
};
// 列操作
const columnAction = (action: string, columnField: string) => {
  const index = columns.value.findIndex(item => item.field === columnField);
  switch (action) {
    case 'visibleToggle': // 显隐
      columns.value[index].hide = !columns.value[index].hide;
      break;
    case 'left': // 列左冻结 左解冻
      columns.value[index].fixed = columns.value[index].fixed === 'left' ? '' : 'left';
      break;
    case 'right': // 列右冻结 右解冻
      columns.value[index].fixed = columns.value[index].fixed === 'right' ? '' : 'right';
      break;
  }
  columns.value = [...columns.value];
  xGrid.value?.refreshColumn();
};

const search = (form: any) => {
  const { name = '', startDate = '' } = form;
  filterList.value = list.filter(
    item => item.areaName.includes(name || '') && item.startDate.includes(startDate || '')
  );
  page.value.currentPage = 1;
  page.value.total = filterList.value.length;
  xGrid.value?.clearFilter();
  getCurrentPageData();
};
// 列拖拽排序
const columsChange = (list: any[]) => {
  columns.value = Object.freeze(list);
};
// 模拟后台接口
const pageChange = (data: VxePagerDefines.PageChangeEventParams) => {
  const { currentPage, pageSize } = data;
  page.value.currentPage = currentPage;
  page.value.pageSize = pageSize;
  getCurrentPageData();
};
onMounted(() => {
  getCurrentPageData();
});

// 模拟后台接口
const delApi = (removeRecords: RowVO[]) => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({
        result: [],
        msg: `delete，${removeRecords.length}条`,
      });
    }, 100);
  });
};

// 模拟后台接口
const saveApi = (insertRecords: RowVO[]) => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({
        result: [],
        msg: `succcess, ${insertRecords.length}条`,
      });
    }, 100);
  });
};
const ageOptions = ref([{ data: { vals: [], sVal: '' } }]);
// 创建一个支持列内容的筛选
VXETable.renderer.add('FilterContent', {
  // 不显示底部按钮，使用自定义的按钮
  showFilterFooter: false,
  // 筛选模板
  renderFilter(renderOpts, params) {
    params.$table = xGrid.value!;
    // params.$panel =xGrid.value!
    return (
      <FilterContent
        v-click-outside={{
          handler: () => {
            xGridHeader.value?.closeFilter();
          },
          capture: true,
        }}
        params={params}
      ></FilterContent>
    );
  },
  // 重置数据方法
  filterResetMethod(params) {
    const { options } = params;
    options.forEach(option => {
      option.data = { vals: [], sVal: '' };
    });
  },
  // 筛选数据方法
  filterMethod(params) {
    const { option, row, column } = params;
    const { vals } = option.data;
    const cellValue = row[column.field];
    const fixRow = Array.from(store.$state.fixRow ?? []);
    if (fixRow.some(item => equalRow(item, row))) {
      return true;
    }
    return vals.includes(cellValue);
  },
});
const gridOptions = reactive<VxeGridProps<RowVO>>({
  border: true,
  keepSource: true,
  printConfig: {},
  importConfig: {},
  exportConfig: {},
  columnConfig: {
    resizable: true,
    useKey: true,
  },
  rowConfig: {
    resizable: true,
    useKey: true,
    isHover: true,
    isCurrent: true,
  },
  scrollY: {
    enabled: true,
    gt: 0,
  },
  pagerConfig: {
    enabled: false,
  },
  editConfig: {
    trigger: 'click',
    mode: 'row',
    showStatus: true,
  },
  toolbarConfig: {
    slots: {
      buttons: 'toolbar_buttons',
    },
    buttons: [
      { name: '这是表格标题' },
      {
        code: 'mark_cancel',
        name: 'app.body.button.markCancel',
        status: 'perfect',
        icon: 'vxe-icon-delete',
      },
      { code: 'save', name: 'app.body.button.save', status: 'perfect', icon: 'vxe-icon-save' },
    ],
    tools: [{ name: '自定义按钮', code: 'myPrint' }],
    perfect: true,

    refresh: {
      icon: 'vxe-icon-refresh',
      iconLoading: 'vxe-icon-refresh roll',
    },
    zoom: {
      iconIn: 'vxe-icon-fullscreen',
      iconOut: 'vxe-icon-minimize',
    },
  },
});

const setHeight = (height: number) => {
  store.$state.rowHeight = height;
  (document.querySelector('.tableWrap') as HTMLElement)?.style.setProperty(
    '--table-row-height',
    height + ''
  );
  rowHeight.value.height = height;
};
const toolbarToolClick = (code: string) => {
  const $grid = xGrid.value;
  if ($grid) {
    switch (code) {
      case 'fullscreen': {
        // $grid.zoom();
        (document.querySelector('.tableWrap') as HTMLElement)?.classList.toggle('fullScreen');
        break;
      }
      case 'refresh': {
        getCurrentPageData();
        break;
      }
    }
  }
};

const open = (index = 1) => {
  ElMessageBox.alert('是否确认执行操作' + index === '1' ? '一' : '二', '提示', {
    // if you want to disable its autofocus
    // autofocus: false,
    confirmButtonText: '确认',
    callback: (action: Action) => {
      ElMessage({
        type: 'info',
        message: `action: ${action}`,
      });
    },
  });
};

watch(
  () => store.$state.focusRefresh,
  () => {
    getCurrentPageData();
  }
);
</script>

<style lang="less">
.vxe-select-option--wrapper {
  position: absolute;
  top: 40px;
}
.keyword-lighten {
  color: #000;
  background-color: #ff0;
}
.operator-cell-active {
  background-color: rgba(49, 150, 154, 0.1);
}
</style>
<style lang="less" scoped>
.tableWrap {
  --table-fix-row: 0;
  --table-row-height: 38;
  height: calc(100% - 26px);
  width: 100%;
  &.fullScreen {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    z-index: 1000;
    background: inherit;
  }
}
.tableHeader {
  :deep(.vxe-table) {
    margin-right: 6px;
  }
  :deep(.vxe-table--body-wrapper) {
    overflow: hidden;
    // overflow-y: scroll;
    min-height: 0 !important;
  }
  :deep(.vxe-table--empty-block) {
    display: none;
  }
}
.tableBody {
  height: calc(100% - 130px - var(--table-row-height) * var(--table-fix-row) * 1px);
  :deep(.vxe-table--body-wrapper) {
    overflow-y: scroll;
  }
}
.table-wrap {
  padding: 16px;
  background-color: #fff;
  .toolbar {
    display: flex;
    justify-content: space-between;
    padding-bottom: 6px;
    margin-bottom: 12px;
    border-bottom: 1px solid #ebebeb;
    .left-tool {
      display: flex;
      align-items: center;
      .total {
        display: flex;
        font-family: 思源黑体;
        font-size: 14px;
        font-weight: normal;
        line-height: 14px;
        text-align: center;
        letter-spacing: 0em;
        white-space: nowrap;
        margin: 0px 16px;

        color: #666666;
        .num {
          color: #099aa0;
        }
      }
    }
    .right-tool {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      .toolIcon {
        font-size: 20px;
        margin-left: 16px;
        cursor: pointer;
        &:focus-within,
        &:hover {
          color: var(--vxe-primary-color);
        }
      }
    }
  }
  .title {
    position: relative;
    font-family: 思源黑体;
    font-size: 16px;
    font-weight: bold;
    line-height: 16px;
    text-align: center;
    letter-spacing: 0em;
    color: #31969a;
    padding-left: 20px;
    white-space: nowrap;

    &::after {
      content: '';
      width: 4px;
      height: 16px;
      border-radius: 10px;
      opacity: 1;

      background: linear-gradient(180deg, #00cb9c 0%, #31969a 99%);
      position: absolute;
      left: 0px;
      top: 0px;
    }
  }
}
.operator-wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  .divied-line {
    height: 12px;
    width: 1px;
    background-color: #d9d9d9;
  }
}

:deep(.vxe-header--column) {
  .vxe-cell--title {
    display: inline-block;
    font-weight: 550;
    // min-width: calc(100% - 50px);
  }
  .vxe-cell--sort {
    margin-left: 11px;
    margin-right: 5px;
  }
  .vxe-cell--sort .vxe-sort--asc-btn,
  .vxe-cell--sort .vxe-sort--desc-btn,
  .vxe-cell--filter {
    display: none;
    i {
      color: rgba(255, 255, 255, 0.5);
    }
  }
  .vxe-cell--sort .vxe-sort--asc-btn,
  .vxe-cell--sort .vxe-sort--desc-btn {
    height: auto;
    line-height: auto;
    color: rgba(255, 255, 255, 0.5);
    margin-bottom: 2px;
    &:hover {
      color: #fff;
    }
  }
  &:hover {
    background-color: #39aeb2;
    .vxe-cell--sort .vxe-sort--asc-btn,
    .vxe-cell--sort .vxe-sort--desc-btn,
    .vxe-cell--filter {
      display: inline-block;
      i {
        color: rgba(255, 255, 255, 0.5);
      }
      &:hover {
        i {
          color: #fff;
        }
      }
    }
  }
  .sort--active {
    display: inline !important;
    color: #fff !important;
  }
}
:deep(.is--filter-active) {
  .vxe-cell--filter {
    display: inline !important;
    .vxe-filter--btn {
      display: inline !important;
      color: #fff !important;
    }
  }
}

.menu-item {
  margin: 0 4px;
  width: 140px;
  padding: 0px 8px;
  display: inline-block;
  line-height: 32px;
  font-family: 思源黑体;
  font-size: 14px;
  font-weight: normal;
  letter-spacing: 0em;

  /* 主色/二级75% */
  color: #4e6469;
  &:hover {
    background-color: rgba(0, 0, 0, 0.06) !important;
    color: #4e6469 !important;
  }
}

.colorpicer {
  font-family: 思源黑体;
  font-size: 14px;
  font-weight: normal;
  letter-spacing: 0em;

  /* 主色/二级75% */
  color: #4e6469;
  .colortitle {
    line-height: 26px;
    margin-bottom: 4px;
  }
  .colorWrap {
    display: flex;
    flex-wrap: wrap;
  }
  .colorItem {
    width: 16px;
    height: 16px;
    border-radius: 2px;
    opacity: 1;

    background: #4eac5b;

    box-sizing: border-box;
    border: 0.5px solid #d9d9d9;
    margin-right: 8px;
    margin-bottom: 4px;
  }
}

.listwrap {
  padding: 10px 0px;
  margin: 4px;
  background-color: #fff;
  max-height: 300px;
  overflow: auto;
  // padding: 0px 15px;
  .list-group-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 104px;
    position: none;
    padding-left: 10px;
    font-family: 思源黑体;
    font-size: 14px;
    font-weight: normal;
    line-height: 28px;
    letter-spacing: 0em;
    cursor: move;
    color: #666666;
    &:hover {
      background-color: rgba(0, 0, 0, 0.06);
    }
    .vxe-icon-menu {
      font-size: 14px;
      cursor: pointer;
      pointer-events: all;
    }
    .icon-group {
      display: flex;
      :deep(i) {
        color: #c7c7c7;
        font-size: 16px;
        cursor: pointer;
        pointer-events: all;
        margin-right: 10px;
      }
    }
  }
}
</style>
